<?php
namespace app\index\controller;

use app\BaseController;
use think\facade\View;
use think\Request;
use app\validate\Test as testValidate;
use think\exception\ValidateException;

use app\common\Test;
//接口通过provider.php绑定实现类，然后依赖注入调用即可
use app\repositories\contracts\DemoInterface;

class Index extends BaseController
{
    public function index(Test $test,DemoInterface $demoInterface)
    {
        $html = '';
        $html .= '<br>根目录<br>'.root_path();
        $html .= '<br>基础目录[根目录下的app目录]<br>'.base_path();
        $html .= '<br>应用目录[当前应用所在的目录，如果是单应用模式则同基础目录，如果是多应用模式，则是app/应用子目录]<br>'.app_path();
        $html .= '<br>配置目录[根目录下的config目录]<br>'.config_path();
        $html .= '<br>运行时目录[框架运行时的目录，单应用模式就是根目录的runtime目录，多应用模式为runtime/应用子目录]<br>'.runtime_path();



        //————————这是依赖注入的使用————————
        //文件在 app/common/Test.php
        $html .= '<br>'.$test->hello();

        //————————这是服务容器的使用————————
        //接口通过provider.php绑定标识和类即可通过助手函数或$this->app调用
        $html .= '<br>'.app('test')->app(); //或者app()->test->app();

        //————————这是门面的使用————————
        //文件在 app/facade/Test.php
        $html .= '<br>'.\app\facade\Test::facade();

        //————————这是接口的使用————————
        //文件在 app/repositories
        //contracts 存放接口文件
        //eloquent 存放接口实现类
        //接口通过provider.php绑定实现类，然后依赖注入调用即可
        $html .= '<br>'.$demoInterface->call();

        //————————这是事件的使用，业务执行完毕后触发某事件————————
        //文件在 app/event/Test.php
        //绑定在 app/index/event.php
        //也可以使用 event('Test');
        //也可以使用 event('app\event\Test');
        //动态绑定事件  Event::bind(['Test' => 'app\event\Test']);
        //动态绑定监听者 Event::listen('Test', 'app\listener\TestListener');
        //动态绑定订阅者 Event::subscribe('app\subscribe\TestSubscribe');
        //闭包写法的监听者 Event::listen('Test', function($user) { });
        //两种模式：

        //一：事件+监听者 触发事件->执行监听者->监听者调用事件方法
        \think\facade\Event::trigger('Test','参数');

        //二：订阅者 触发事件->订阅者解析事件标识到对应的on方法
        \think\facade\Event::trigger('Test2','参数');

        //断点测试
        //dd('输出测试');
        //halt('输出测试');

        //如何添加更多应用？
        //1.添加目录及应用结构（可直接复制index应用，但注意修改命名空间）：app/应用名称
        //2.public/下复制admin.php修改为 应用名.php
        //3.config/app.php下 app_map配置添加 '应用名' => '应用名'
        //4.浏览器访问 localhost/应用名 即可访问
        return '<h1>多应用模式-我是'.app('http')->getName().'应用</h1>'.$html;
    }

    public function hello($name = 'Index')
    {
        return 'hello,' . $name;
    }

    //————————这是中间件的使用，中间件通过后访问此方法————————
    //给当前控制器添加中间件
    //protected $middleware = [\app\middleware\Test::class];

    // 中间件文件在               app/middleware/Test.php
    // 路由绑定中间件来访问此方法    app/index/route/index.php
    public function mid(Request $request)
    {
        return '测试中间件：' . $request->mid;
    }


    //————————这是请求的使用————————
    //方法	        含义
    //host	        当前访问域名或者IP
    //scheme	    当前访问协议
    //port	        当前访问的端口
    //remotePort	当前请求的REMOTE_PORT
    //protocol	    当前请求的SERVER_PROTOCOL
    //contentType	当前请求的CONTENT_TYPE
    //domain	    当前包含协议的域名
    //subDomain	    当前访问的子域名
    //panDomain	    当前访问的泛域名
    //rootDomain	当前访问的根域名
    //url	        当前完整URL
    //baseUrl	    当前URL（不含QUERY_STRING）
    //query	        当前请求的QUERY_STRING参数
    //baseFile	    当前执行的文件 包含域名 baseFile(true)
    //root	        URL访问根地址
    //rootUrl	    URL访问根目录
    //pathinfo	    当前请求URL的pathinfo信息（含URL后缀）
    //ext	        当前URL的访问后缀
    //time	        获取当前请求的时间
    //type	        当前请求的资源类型
    //method	    当前请求类型
    //rule	        当前请求的路由对象实例
    //controller    当前控制器
    //action        当前方法
    //app('http')->getName(); 当前应用
    public function request(Request $request)
    {
        //halt(request()->param('name'));
        //halt(app('http')->getName());

        //获取参数
        //方法	    描述
        //param	    获取当前请求的变量
        //get	    获取 $_GET 变量
        //post	    获取 $_POST 变量
        //put	    获取 PUT 变量
        //delete	获取 DELETE 变量
        //session	获取 SESSION 变量
        //cookie	获取 $_COOKIE 变量
        //request	获取 $_REQUEST 变量
        //server	获取 $_SERVER 变量
        //env	    获取 $_ENV 变量
        //route	    获取 路由（包括PATHINFO） 变量
        //middleware获取 中间件赋值/传递的变量
        //file	    获取 $_FILES 变量
        //all   	获取包括 $_FILES 变量在内的请求变量，相当于param+file

        // 获取所有参数
        //halt($request->all());

        // 获取某个参数
        //halt($request->param('name'));

        // 只获取当前请求的id和name变量,还可以设置默认值和请求类型 等效$request->get(['id', 'name']);
        //halt($request->only(['id'=>0,'name'],'get'));

        // 排除post请求中的id和name参数
        //halt($request->except(['id','name'], 'post'));

        //修饰符	作用
        //s	    强制转换为字符串类型
        //d	    强制转换为整型类型
        //b	    强制转换为布尔类型
        //a	    强制转换为数组类型
        //f	    强制转换为浮点类型
        //halt($request->get('name/s'));

        //助手函数
        //判断变量是否定义
        //input('?get.id');
        //input('?post.name');

        //获取PARAM参数
        //input('param.name'); // 获取单个参数
        //input('param.'); // 获取全部参数
        //下面是等效的
        //input('name');
        //input('');

        //获取GET参数
        // 获取单个变量
        //input('get.id');
        // 使用过滤方法获取 默认为空字符串
        //input('get.name');
        // 获取全部变量
        //input('get.');

        //使用过滤方法
        //input('get.name','','htmlspecialchars'); // 获取get变量 并用htmlspecialchars函数过滤
        //input('username','','strip_tags'); // 获取param变量 并用strip_tags函数过滤
        //input('post.name','','org\Filter::safeHtml'); // 获取post变量 并用org\Filter类的safeHtml方法过滤

        //使用变量修饰符
        //input('get.id/d');
        //input('post.name/s');
        //input('post.ids/a');

        // 判断请求类型
        //用途	            方法
        //获取当前请求类型	    method
        //判断是否GET请求	    isGet
        //判断是否POST请求	isPost
        //判断是否PUT请求	    isPut
        //判断是否DELETE请求	isDelete
        //判断是否AJAX请求	isAjax
        //判断是否PJAX请求	isPjax
        //判断是否JSON请求	isJson
        //判断是否手机访问	    isMobile
        //判断是否HEAD请求	isHead
        //判断是否PATCH请求	isPatch
        //判断是否OPTIONS请求	isOptions
        //判断是否为CLI执行	isCli
        //判断是否为CGI模式	isCgi

        //伪装请求
        //<form method="post" action="">
        //<input type="hidden" name="_method" value="PUT" > 将被识别为PUT请求而非post
        //</form>
        //AJAX请求伪装
        //http://localhost/index?_ajax=1
        //PJAX请求伪装
        //http://localhost/index?_pjax=1
        //获取原始请求类型
        //$request->method(true);

        //header头信息获取
        //Request::header('user-agent');
        //或
        //$info = Request::header();
        //echo $info['accept'];
        //echo $info['accept-encoding'];
        //echo $info['user-agent'];

        //路由参数 以下案例为 url---控制器接收 一一对应
        //http://serverName/index.php/blog/read/blog_id/5 //这里知识点是url的下划线会转为驼峰写法传到控制器
        //public function read($blogId = 0)

        //http://serverName/index.php/blog/archive/year/2016/month/06
        //public function archive($year, $month='01')

        halt($request->ext());

        return '请求测试';
    }

    //————————这是响应的使用————————
    public function response()
    {
        //输出类型	    快捷方法	    对应Response类
        //HTML输出	    response	\think\Response
        //渲染模板输出	view	    \think\response\View
        //JSON输出	    json	    \think\response\Json
        //JSONP输出	    jsonp	    \think\response\Jsonp
        //XML输出	    xml	        \think\response\Xml
        //页面重定向	    redirect	\think\response\Redirect
        //附件下载	    download	\think\response\File

        //常用头快捷方法
        //方法名	        作用
        //lastModified	设置Last-Modified头信息
        //expires	    设置Expires头信息
        //eTag	        设置ETag头信息
        //cacheControl	设置Cache-control头信息
        //contentType	设置Content-Type头信息

        //Cookie相关
        //写入    response()->cookie('name', 'value', 600);

        //重定向
        //redirect('index/mid');
        //redirect('index/mid')->with('name','hahaha'); //闪存，仅本次跳转有效

        //文件下载
        //方法	    描述
        //name	    命名下载文件
        //expire	下载有效期
        //isContent	是否为内容下载
        //mimeType	设置文件的mimeType类型
        //force	    是否强制下载（V6.0.3+） 可用于浏览器查看图片而非下载等

        //download('image.jpg', 'my.jpg')->expire(300); 第一个参数是服务器路径，第二个参数是下载文件名，下载有效期300秒
        //$data = '这是一个测试文件';
        //return download($data, 'test.txt', true);

        $data = ['name' => 'thinkphp', 'status' => '1'];
        return json($data,201)
            ->header(['Cache-control' => 'no-cache,must-revalidate'])
            ->allowCache(false); // 关闭当前请求缓存
    }

    //————————这是验证器的使用————————
    //引入验证器 use app\validate\验证器类名; （本案例引入并设置了别名为testValidate）
    //引入异常类 use think\exception\ValidateException;
    public function testValidate()
    {
        try {
            validate(testValidate::class)->check([
                'name'  => 'thinkphp',
                'email' => 'thinkphp@qq.com',
            ]);
        } catch (ValidateException $e) {
            // 验证失败 输出错误信息
            dump($e->getError());
        }

        //批量验证，输出全部错误
        //	try {
        //		$result = validate(User::class)->batch(true)->check([
        //			'name'  => 'thinkphp',
        //			'email' => 'thinkphp@qq.com',
        //		    ]);
        //
        //		if (true !== $result) {
        //		    // 验证失败 输出错误信息
        //		    dump($result);
        //		}
        //	} catch (ValidateException $e) {
        //            // 验证失败 输出错误信息
        //            dump($e->getError());
        //        }
        //    }

        //动态验证（独立验证）
        //$validate = \think\facade\Validate::rule('age', 'number|between:1,120')
        //->rule([
        //    'name'  => 'require|max:25',
        //    'email' => 'email'
        //]);

        //$validate = Validate::rule([
        //    'name'  => function($value) {
        //        return 'thinkphp' == strtolower($value) ? true : false;
        //    },
        //]);

        //
        //$data = [
        //    'name'  => 'thinkphp',
        //    'email' => 'thinkphp@qq.com'
        //];
        //
        //if (!$validate->check($data)) {
        //    dump($validate->getError());
        //}

        //错误信息获取
        //$validate = new \app\validate\Test;
        //$result = $validate->check($data);
        //
        //if(!$result){
        //    echo $validate->getError();
        //}
    }

    /***
     * 测试请求API接口（无需登录，签名验证）
     */
    public function testApi()
    {
        return View::fetch();
    }

}
